package com.jh.paymentchannel.util.yipiaolian;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.*;
import java.util.*;

public class EasyPaySDK {
    private static final Logger logger = LoggerFactory.getLogger(EasyPaySDK.class);
    private static final String ENCODING = "UTF-8";
    private static final String URL = "https://service.epaylinks.cn:8443/mp/trade";

    /**
     * 去除sign和空值的参数
     * 签名前调用，方法仅供参考
     * @param parameters 需要发送的参数
     * @return
     */
    public static String withoutSignOrEmptyValue(SortedMap<String, String> parameters) {
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<String,String>> es = parameters.entrySet();
        Iterator<Map.Entry<String,String>> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry<String,String> entry = it.next();
            String k = entry.getKey();
            String v = entry.getValue();
            if ((v != null) && (!"".equals(v)) && (!"sign".equals(k)) && (!"key".equals(k))) {
                sb.append(k + "=" + v + "&");
            }
        }
        String dataString = sb.toString();
        return dataString.substring(0, dataString.length() - 1);
    }

    /**
     * 组装发送请求数据
     * 发送请求钱调用，方法仅供参考
     * @param reqMap
     * @param encoding
     * @return
     */
    public static String toRequestString(Map<String ,String> reqMap, String encoding) {
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<String,String>> es = reqMap.entrySet();
        Iterator<Map.Entry<String,String>> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry<String,String> entry = it.next();
            String k = entry.getKey();
            String v = entry.getValue();
            if ((v != null) && (!"".equals(v))) {
                if("sign".equals(k)) {
                    try {
                        v = URLEncoder.encode(v, encoding);
                    } catch (UnsupportedEncodingException e) {
                        logger.error(e.getMessage(), e);
                    }
                }
                sb.append(k + "=" + v + "&");
            }
        }
        String dataString = sb.toString();
        return dataString.substring(0, dataString.length() - 1);
    }

    /**
     * 签名方法
     * @param map 需要发送的参数 map
     * @param privateKey 私钥
     * @return
     * @throws Exception
     */
    public static String sign(SortedMap<String, String> map, PrivateKey privateKey) throws Exception {
        String unSignedString = EasyPaySDK.withoutSignOrEmptyValue(map);
        byte[] signByte = EasyPaySDK.sign(unSignedString, privateKey);
        return new BASE64Encoder().encode(signByte).replaceAll("[\\s*\t\n\r]", "");
    }

    private static byte[] sign(String dataString, PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(dataString.getBytes("UTF-8"));
        return signature.sign();
    }

    /**
     * 解签
     * @param map 收到的报文参数
     * @param publicKey 从epaylinks_pfx.cer取出公钥
     * @return
     * @throws Exception
     */
    public static boolean unSign(SortedMap map, PublicKey publicKey) throws Exception {
        StringBuffer sb = new StringBuffer();
        Set<Map.Entry<String ,String>> es = map.entrySet();
        Iterator<Map.Entry<String ,String>> it = es.iterator();
        while(it.hasNext()) {
            Map.Entry<String ,String> entry = it.next();
            String k = entry.getKey();
            String v = entry.getValue();
            if(!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }
        String dataString = sb.toString();
        dataString = dataString.substring(0,dataString.length()-1);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(dataString.getBytes("utf-8"));
        return signature.verify(new BASE64Decoder().decodeBuffer((String) map.get("sign")));
    }

    /**
     * 获取 encryptedInfo 字段
     * @param publicKey
     * @return
     * @throws Exception
     */
    public static String getEncryptedInfo(PublicKey publicKey, String CVN2, String expired) throws Exception {
        String clearText = "cvn2="+CVN2+"&expired="+expired;
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(1, publicKey);
        byte[] r1 = cipher.doFinal(clearText.getBytes("UTF-8"));
        String encryptedInfo = new BASE64Encoder().encode(r1).replaceAll("[\\s*\t\n\r]", "");
        return encryptedInfo;
    }

    /**
     * 发送报文
     * @param reqMap
     * @return
     * @throws Exception
     */
    public static String sendPost(Map<String ,String> reqMap) throws Exception {
        String requestString = toRequestString(reqMap, ENCODING);
        logger.info(reqMap.get("outOrderNo") + " 上送参数：" + requestString);
        String result = HttpUtils.sendPost(URL, requestString.getBytes(ENCODING), ENCODING);
        logger.info(reqMap.get("outOrderNo") + " 接受报文：" + result);
        return result;
    }
}